package com.qingzhou.framework.aspect;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.qingzhou.common.constants.UserConstant;
import com.qingzhou.common.utils.SecurityUtil;
import com.qingzhou.common.web.domain.BaseEntity;
import com.qingzhou.common.web.domain.model.LoginUser;
import com.qingzhou.common.web.domain.entity.SysRole;
import com.qingzhou.common.web.domain.entity.SysUser;
import com.qingzhou.framework.annotation.QzDataScope;
import org.noear.solon.core.aspect.Invocation;
import org.noear.solon.core.aspect.MethodInterceptor;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据过滤处理
 * @author xm
 */
public class DataScopeAspect<T extends BaseEntity> implements MethodInterceptor {

    @SuppressWarnings("unchecked")
    @Override
    public Object doIntercept(Invocation inv) throws Throwable {
        QzDataScope qzDataScope = inv.method().getAnnotation(QzDataScope.class);
        for (Object entity : inv.args()) {
            if(entity instanceof BaseEntity) {
                T t = (T) entity;
                handleDataScope(t, qzDataScope);
            }
        }
        return inv.invoke();
    }

    /**
     * 拼接数据权限 sql
     * @param t
     * @param qzDataScope
     */
    private void handleDataScope(T t, QzDataScope qzDataScope) {
        // 拼接权限sql前先清空 dataScope参数防止注入
        t.setDataScopeSql(StrUtil.EMPTY);
        // 获取当前的用户
        LoginUser loginUser = SecurityUtil.getLoginUser();
        if (ObjectUtil.isNotNull(loginUser)) {
            SysUser sysUser = loginUser.getSysUser();
            // 如果是超级管理员，则不过滤数据
            if (ObjectUtil.isNotNull(sysUser) && !SecurityUtil.isAdmin(loginUser.getUserid())) {
                StringBuilder sqlString = new StringBuilder();
                List<String> conditions = new ArrayList<>();
                for (SysRole sysRole : sysUser.getRoles()) {
                    String ds = sysRole.getDataScope();
                    if (!UserConstant.DATA_SCOPE_CUSTOM.equals(ds) && conditions.contains(ds)) {
                        continue;
                    }
                    if (UserConstant.DATA_SCOPE_ALL.equals(ds)) {
                        sqlString = new StringBuilder();
                        conditions.add(ds);
                        break;
                    } else if (UserConstant.DATA_SCOPE_CUSTOM.equals(ds)) {
                        sqlString.append(StrUtil.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", qzDataScope.deptAlias(), sysRole.getRoleId()));
                    } else if (UserConstant.DATA_SCOPE_DEPT.equals(ds)) {
                        sqlString.append(StrUtil.format(" OR {}.dept_id = {} ", qzDataScope.deptAlias(), sysUser.getDeptId()));
                    } else if (UserConstant.DATA_SCOPE_DEPT_AND_CHILD.equals(ds)) {
                        sqlString.append(StrUtil.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", qzDataScope.deptAlias(), sysUser.getDeptId(), sysUser.getDeptId()));
                    } else if (UserConstant.DATA_SCOPE_SELF.equals(ds)) {
                        if (StrUtil.isNotBlank(qzDataScope.userAlias())) {
                            sqlString.append(StrUtil.format(" OR {}.user_id = {} ", qzDataScope.userAlias(), sysUser.getUserId()));
                        } else {
                            // 数据权限为仅本人且没有userAlias别名不查询任何数据
                            sqlString.append(StrUtil.format(" OR {}.dept_id = 0 ", qzDataScope.deptAlias()));
                        }
                    }
                    conditions.add(ds);
                }

                // 多角色情况下，所有角色都不包含传递过来的权限字符，这个时候sqlString也会为空，所以要限制一下,不查询任何数据
                if (CollectionUtil.isEmpty(conditions)) {
                    sqlString.append(StrUtil.format(" OR {}.dept_id = 0 ", qzDataScope.deptAlias()));
                }
                if (StrUtil.isNotBlank(sqlString.toString())) {
                    t.setDataScopeSql(" AND (" + sqlString.substring(4) + ")");
                }
            }
        }
    }

}
